nanopyx.core.generate.beads

  1import numpy as np
  2from math import sqrt
  3from skimage.filters import gaussian
  4from skimage.transform import EuclideanTransform, warp
  5
  6from ..transform.blocks import assemble_frame_from_blocks
  7
  8
  9def generate_random_position(n_rows, n_cols):
 10    """
 11    Generates a random position given number of rows and columns.
 12    :param n_rows: int; number of rows
 13    :param n_cols: int; number of columns
 14    :return: int, int; random position constrained to 0.1 and 0.9 of n_rows and n_cols
 15    """
 16
 17    min_r = int(n_rows * 0.1)
 18    max_r = int(n_rows * 0.9)
 19
 20    min_c = int(n_cols * 0.1)
 21    max_c = int(n_cols * 0.9)
 22
 23    r = np.random.randint(min_r, max_r)
 24    c = np.random.randint(min_c, max_c)
 25
 26    return r, c
 27
 28def generate_image(n_objects=10, shape=(2, 300, 300), dtype=np.float16):
 29    """
 30    Generates a random image with objects in random positions
 31    :param n_objects: int; number of objects to generate
 32    :param shape: tuple; with shape (z, y, x)
 33    :param dtype: data type to be used in the generated numpy array
 34    :return: numpy array with shape (z, y, x) and defined data type and n_objects
 35    """
 36
 37    img = np.zeros(shape).astype(dtype)
 38
 39    n_rows = img.shape[1]
 40    n_cols = img.shape[2]
 41
 42    for i in range(n_objects):
 43        r, c = generate_random_position(n_rows, n_cols)
 44        img[:, r, c] = np.finfo(np.float16).max
 45
 46    for i in range(img.shape[0]):
 47        img[i] = gaussian(img[i], sigma=3)
 48
 49    return img
 50
 51def generate_timelapse_drift(n_objects=10, shape=(10, 300, 300), dtype=np.float16, drift=None,
 52                             drift_mode="directional"):
 53    """
 54    Generate random timelapse image with drift over time.
 55    :param n_objects: int; number of objects to generate
 56    :param shape: tuple; with shape (t, y, x)
 57    :param dtype: data type to be used in the generated numpy array
 58    :param drift: None or int; number of pixels corresponding to drift between frames. If None, automatic drift is
 59    calculated based on 0.02 of image dimensions.
 60    :param drift_mode: str; "directional" (default) or "random";
 61    :return: numpy array with shape (t, y, x) and defined data type and n_objects
 62    """
 63
 64    if drift is None:
 65        drift = min(shape[1]*0.02, shape[2]*0.02)
 66
 67    img = generate_image(n_objects=n_objects, shape=shape, dtype=dtype)
 68
 69    if drift_mode == "directional":
 70        transformation_matrix = EuclideanTransform(translation=(-drift, -drift))
 71        for i in range(shape[0]-1):
 72            img[i+1] = warp(img[i], transformation_matrix.inverse, order=3, preserve_range=True)
 73
 74    elif drift_mode == "random":
 75        for i in range(shape[0]-1):
 76
 77            state = np.random.randint(0, 3)
 78
 79            if state == 1:
 80                transformation_matrix = EuclideanTransform(translation=(-sqrt(drift), -sqrt(drift)))
 81            elif state == 2:
 82                transformation_matrix = EuclideanTransform(translation=(-sqrt(drift), sqrt(drift)))
 83            elif state == 3:
 84                transformation_matrix = EuclideanTransform(translation=(sqrt(drift), -sqrt(drift)))
 85            else:
 86                transformation_matrix = EuclideanTransform(translation=(sqrt(drift), sqrt(drift)))
 87
 88            img[i+1] = warp(img[i], transformation_matrix.inverse, order=3, preserve_range=True)
 89
 90    return img
 91
 92def generate_channel_misalignment():
 93    """
 94    Generates an image with shape (3, 300, 300) with 1 object centered on each 3x3 block of the image.
 95    Slices corresponding to channel 2 and 3 are shifted relative to channel 1 (template).
 96    :return: numpy array of shape (3, 300, 300) corresponding to a random image with misalignment between channels.
 97    """
 98
 99    n_blocks = 3
100    h = 300
101    w = 300
102
103    block_img = np.zeros((int(h/n_blocks), int(w/n_blocks)))
104    block_h = int(h / n_blocks)
105    block_w = int(w / n_blocks)
106    block_img[int(block_h/2), int(block_w/2)] = 1
107    block_img = gaussian(block_img, sigma=3)
108
109    ref_channel = np.zeros((h, w))
110    misaligned_blocks = []
111    misaligned_blocks_2 = []
112
113    for x_i in range(n_blocks):
114        for y_i in range(n_blocks):
115            ref_channel[y_i*block_h:y_i*block_h+block_h, x_i*block_w:x_i*block_w+block_w] += block_img
116
117    misalignments = [(-3, -3), (-3, 0), (-3, 3), (0, -3), (0, 0), (0, 3), (3, -3), (3, 0), (3, 3)]
118
119    for mis in misalignments:
120        block_img = np.zeros((int(h/n_blocks), int(w/n_blocks)))
121        block_h = h / n_blocks
122        block_w = w / n_blocks
123        block_img[int(block_h/2)+mis[0], int(block_w/2)+mis[1]] = 1
124        block_img = gaussian(block_img, sigma=3)
125        misaligned_blocks.append(block_img)
126
127    misalignments.reverse()
128
129    for mis in misalignments:
130        block_img = np.zeros((int(h/n_blocks), int(w/n_blocks)))
131        block_h = h / n_blocks
132        block_w = w / n_blocks
133        block_img[int(block_h/2)+mis[0], int(block_w/2)+mis[1]] = 1
134        block_img = gaussian(block_img, sigma=3)
135        misaligned_blocks_2.append(block_img)
136
137    misaligned_channel = assemble_frame_from_blocks(np.array(misaligned_blocks), 3, 3)
138    misaligned_channel_2 = assemble_frame_from_blocks(np.array(misaligned_blocks_2), 3, 3)
139
140    return np.array([ref_channel, misaligned_channel, misaligned_channel_2]).astype(np.float16)
def generate_random_position(n_rows, n_cols):
10def generate_random_position(n_rows, n_cols):
11    """
12    Generates a random position given number of rows and columns.
13    :param n_rows: int; number of rows
14    :param n_cols: int; number of columns
15    :return: int, int; random position constrained to 0.1 and 0.9 of n_rows and n_cols
16    """
17
18    min_r = int(n_rows * 0.1)
19    max_r = int(n_rows * 0.9)
20
21    min_c = int(n_cols * 0.1)
22    max_c = int(n_cols * 0.9)
23
24    r = np.random.randint(min_r, max_r)
25    c = np.random.randint(min_c, max_c)
26
27    return r, c

Generates a random position given number of rows and columns.

Parameters
  • n_rows: int; number of rows
  • n_cols: int; number of columns
Returns

int, int; random position constrained to 0.1 and 0.9 of n_rows and n_cols

def generate_image(n_objects=10, shape=(2, 300, 300), dtype=<class 'numpy.float16'>):
29def generate_image(n_objects=10, shape=(2, 300, 300), dtype=np.float16):
30    """
31    Generates a random image with objects in random positions
32    :param n_objects: int; number of objects to generate
33    :param shape: tuple; with shape (z, y, x)
34    :param dtype: data type to be used in the generated numpy array
35    :return: numpy array with shape (z, y, x) and defined data type and n_objects
36    """
37
38    img = np.zeros(shape).astype(dtype)
39
40    n_rows = img.shape[1]
41    n_cols = img.shape[2]
42
43    for i in range(n_objects):
44        r, c = generate_random_position(n_rows, n_cols)
45        img[:, r, c] = np.finfo(np.float16).max
46
47    for i in range(img.shape[0]):
48        img[i] = gaussian(img[i], sigma=3)
49
50    return img

Generates a random image with objects in random positions

Parameters
  • n_objects: int; number of objects to generate
  • shape: tuple; with shape (z, y, x)
  • dtype: data type to be used in the generated numpy array
Returns

numpy array with shape (z, y, x) and defined data type and n_objects

def generate_timelapse_drift( n_objects=10, shape=(10, 300, 300), dtype=<class 'numpy.float16'>, drift=None, drift_mode='directional'):
52def generate_timelapse_drift(n_objects=10, shape=(10, 300, 300), dtype=np.float16, drift=None,
53                             drift_mode="directional"):
54    """
55    Generate random timelapse image with drift over time.
56    :param n_objects: int; number of objects to generate
57    :param shape: tuple; with shape (t, y, x)
58    :param dtype: data type to be used in the generated numpy array
59    :param drift: None or int; number of pixels corresponding to drift between frames. If None, automatic drift is
60    calculated based on 0.02 of image dimensions.
61    :param drift_mode: str; "directional" (default) or "random";
62    :return: numpy array with shape (t, y, x) and defined data type and n_objects
63    """
64
65    if drift is None:
66        drift = min(shape[1]*0.02, shape[2]*0.02)
67
68    img = generate_image(n_objects=n_objects, shape=shape, dtype=dtype)
69
70    if drift_mode == "directional":
71        transformation_matrix = EuclideanTransform(translation=(-drift, -drift))
72        for i in range(shape[0]-1):
73            img[i+1] = warp(img[i], transformation_matrix.inverse, order=3, preserve_range=True)
74
75    elif drift_mode == "random":
76        for i in range(shape[0]-1):
77
78            state = np.random.randint(0, 3)
79
80            if state == 1:
81                transformation_matrix = EuclideanTransform(translation=(-sqrt(drift), -sqrt(drift)))
82            elif state == 2:
83                transformation_matrix = EuclideanTransform(translation=(-sqrt(drift), sqrt(drift)))
84            elif state == 3:
85                transformation_matrix = EuclideanTransform(translation=(sqrt(drift), -sqrt(drift)))
86            else:
87                transformation_matrix = EuclideanTransform(translation=(sqrt(drift), sqrt(drift)))
88
89            img[i+1] = warp(img[i], transformation_matrix.inverse, order=3, preserve_range=True)
90
91    return img

Generate random timelapse image with drift over time.

Parameters
  • n_objects: int; number of objects to generate
  • shape: tuple; with shape (t, y, x)
  • dtype: data type to be used in the generated numpy array
  • drift: None or int; number of pixels corresponding to drift between frames. If None, automatic drift is calculated based on 0.02 of image dimensions.
  • drift_mode: str; "directional" (default) or "random";
Returns

numpy array with shape (t, y, x) and defined data type and n_objects

def generate_channel_misalignment():
 93def generate_channel_misalignment():
 94    """
 95    Generates an image with shape (3, 300, 300) with 1 object centered on each 3x3 block of the image.
 96    Slices corresponding to channel 2 and 3 are shifted relative to channel 1 (template).
 97    :return: numpy array of shape (3, 300, 300) corresponding to a random image with misalignment between channels.
 98    """
 99
100    n_blocks = 3
101    h = 300
102    w = 300
103
104    block_img = np.zeros((int(h/n_blocks), int(w/n_blocks)))
105    block_h = int(h / n_blocks)
106    block_w = int(w / n_blocks)
107    block_img[int(block_h/2), int(block_w/2)] = 1
108    block_img = gaussian(block_img, sigma=3)
109
110    ref_channel = np.zeros((h, w))
111    misaligned_blocks = []
112    misaligned_blocks_2 = []
113
114    for x_i in range(n_blocks):
115        for y_i in range(n_blocks):
116            ref_channel[y_i*block_h:y_i*block_h+block_h, x_i*block_w:x_i*block_w+block_w] += block_img
117
118    misalignments = [(-3, -3), (-3, 0), (-3, 3), (0, -3), (0, 0), (0, 3), (3, -3), (3, 0), (3, 3)]
119
120    for mis in misalignments:
121        block_img = np.zeros((int(h/n_blocks), int(w/n_blocks)))
122        block_h = h / n_blocks
123        block_w = w / n_blocks
124        block_img[int(block_h/2)+mis[0], int(block_w/2)+mis[1]] = 1
125        block_img = gaussian(block_img, sigma=3)
126        misaligned_blocks.append(block_img)
127
128    misalignments.reverse()
129
130    for mis in misalignments:
131        block_img = np.zeros((int(h/n_blocks), int(w/n_blocks)))
132        block_h = h / n_blocks
133        block_w = w / n_blocks
134        block_img[int(block_h/2)+mis[0], int(block_w/2)+mis[1]] = 1
135        block_img = gaussian(block_img, sigma=3)
136        misaligned_blocks_2.append(block_img)
137
138    misaligned_channel = assemble_frame_from_blocks(np.array(misaligned_blocks), 3, 3)
139    misaligned_channel_2 = assemble_frame_from_blocks(np.array(misaligned_blocks_2), 3, 3)
140
141    return np.array([ref_channel, misaligned_channel, misaligned_channel_2]).astype(np.float16)

Generates an image with shape (3, 300, 300) with 1 object centered on each 3x3 block of the image. Slices corresponding to channel 2 and 3 are shifted relative to channel 1 (template).

Returns

numpy array of shape (3, 300, 300) corresponding to a random image with misalignment between channels.